package com.sdjzu.wangfuying.disableautobrightness.ui;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import com.sdjzu.wangfuying.disableautobrightness.Config;
import com.sdjzu.wangfuying.disableautobrightness.R;
import com.sdjzu.wangfuying.disableautobrightness.base.BaseActivity;
import com.sdjzu.wangfuying.disableautobrightness.bean.remote.Package;
import com.sdjzu.wangfuying.disableautobrightness.repositary.ApiService;
import com.sdjzu.wangfuying.disableautobrightness.util.GameModeUtil;
import com.sdjzu.wangfuying.disableautobrightness.util.StorageUtil;

import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;

import static com.sdjzu.wangfuying.disableautobrightness.Config.BROADCAST_INTENT;
import static com.sdjzu.wangfuying.disableautobrightness.ui.GuideActivity.REQUIRED_PERMISSIONS;
import static com.sdjzu.wangfuying.disableautobrightness.util.GameModeUtil.ensureConfigurationOnly;
import static com.sdjzu.wangfuying.disableautobrightness.util.GameModeUtil.isGameMode;
import static com.sdjzu.wangfuying.disableautobrightness.util.PackageUtil.getApplicationNameByPackageName;

public class ConfiguredPackagesActivity extends BaseActivity {
    @BindView(R.id.activity_configured_packages_recycler)
    RecyclerView mRecyclerView;
    @BindView(R.id.activity_configured_packages_fab)
    FloatingActionButton mFloatingActionButton;
    @BindView(R.id.activity_configured_packages_swipe_refresh_layout)
    SwipeRefreshLayout mSwipeRefreshLayout;

    private ConfiguredPackagesAdapter adapter;

    private ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
        //同来设置 拖拽移动，或移动删除
        @Override
        public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
            return makeMovementFlags(0, ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT);
        }

        //在拖动中不断的回调这个方法
        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
            return false;
        }

        //处理侧滑
        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
            int position = viewHolder.getAdapterPosition();
            final Package pkg = adapter.packages.remove(position);
            // do remove
            GameModeUtil.disableGameMode(getContext(), pkg.getPackageName());
            adapter.notifyItemRemoved(position);
            // show snack bar for undo
            Snackbar.make(mFloatingActionButton, R.string.activity_configured_package_delete_package_ok, Snackbar.LENGTH_SHORT)
                    .setAction(R.string.activity_configured_package_snack_undo, v -> {
                        if (GameModeUtil.enableGameMode(getContext(), pkg.getPackageName())) {
                            adapter.packages.add(pkg);
                            adapter.notifyDataSetChanged();
                        } else {
                            Toast.makeText(getContext(), R.string.activity_configured_package_cannot_resume, Toast.LENGTH_SHORT).show();
                        }
                    })
                    .show();
        }
    });

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_configured_packages);

        // init views
        adapter = new ConfiguredPackagesAdapter();
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        mRecyclerView.setAdapter(adapter);
        itemTouchHelper.attachToRecyclerView(mRecyclerView);

        // setup listeners
        mSwipeRefreshLayout.setOnRefreshListener(this::updatePackageList);

        updatePackageList();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    @OnClick(R.id.activity_configured_packages_fab)
    void addPackageItem(FloatingActionButton button) {
        Intent intent = new Intent(getContext(), SelectPackageItemActivity.class);
        startActivityForResult(intent, 0x0);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (0x0 == requestCode) {
            updatePackageList();
        }
    }

    private void updatePackageList() {
        new GatherConfiguredPackagesTask(getContext(), adapter, mSwipeRefreshLayout).execute();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_configured_packages, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.activity_configured_packages_menu_get_default_package_list:
                getDefaultPackageList();
                break;
            case R.id.activity_configured_packages_menu_setting:
                Intent intent = new Intent(getContext(), GuideActivity.class);
                intent.putExtra("standby", true);
                startActivity(intent);
                break;
            default:
                return super.onOptionsItemSelected(item);
        }
        return true;
    }

    private void getDefaultPackageList() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Config.URL_BASE)
                .build();
        //获取接口实例
        ApiService apiService = retrofit.create(ApiService.class);
        //调用方法得到一个Call
        Call<ResponseBody> call = apiService.getDefaultPackageList();
        //进行网络请求
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                // parse json array and update package list config
                String content = "[]";
                if (response.body() != null) {
                    content = IoUtil.read(response.body().byteStream(), CharsetUtil.CHARSET_UTF_8);
                }
                parsePackageList(content);
                // update recycler list
                updatePackageList();

                // notify to monitor service
                sendBroadcast(new Intent(BROADCAST_INTENT));
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                runOnUiThread(() -> Toast.makeText(getContext(), R.string.activity_configured_packages_toast_get_default_package_list_failed, Toast.LENGTH_SHORT).show());
            }
        });
    }

    private void parsePackageList(String content) {
        Gson gson = new GsonBuilder().create();
        JsonArray jsonArray = new JsonParser().parse(content).getAsJsonArray();
        if (!checkPermissions(REQUIRED_PERMISSIONS)) {
            Toast.makeText(getContext(), R.string.activity_guide_toast_no_permission_granted, Toast.LENGTH_SHORT).show();
            showTipsDialog();
            return;
        }
        boolean noError = true;
        for (int i = 0; i < jsonArray.size(); i++) {
            Package packag = gson.fromJson(jsonArray.get(i), Package.class);
            noError = updatePackageIndex(packag) && noError;
        }
        if (noError) {
            Toast.makeText(getContext(), R.string.activity_configured_packages_toast_get_default_package_list_ok, Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(getContext(), R.string.activity_configured_packages_toast_get_default_package_list_failed, Toast.LENGTH_SHORT).show();
        }
    }

    private boolean updatePackageIndex(Package packag) {
        // create a folder named `packageName`
        if (!ensureConfigurationOnly(getContext(), packag.getPackageName())) {
            Toast.makeText(getContext(), R.string.activity_configured_packages_toast_make_dir_failed, Toast.LENGTH_SHORT).show();
            return false;
        } else {
            return true;
        }
    }

    private static class GatherConfiguredPackagesTask extends AsyncTask<Object, Integer, List<Package>> {
        private final ConfiguredPackagesAdapter adapter;
        private final WeakReference<SwipeRefreshLayout> swipeRefreshLayout;
        private final WeakReference<Context> context;

        GatherConfiguredPackagesTask(Context context, ConfiguredPackagesAdapter adapter, SwipeRefreshLayout swipeRefreshLayout) {
            this.context = new WeakReference<>(context);
            this.adapter = adapter;
            this.swipeRefreshLayout = new WeakReference<>(swipeRefreshLayout);
        }

        @Override
        protected List<Package> doInBackground(Object... objects) {
            File dataDirectory = StorageUtil.getExternalFilesDir(context.get());
            File[] enablePackagesFiles = dataDirectory.listFiles(pathname -> isGameMode(context.get(), pathname.getName()));
            List<Package> packages = new ArrayList<>(enablePackagesFiles.length);
            for (File enablePackagesFile : enablePackagesFiles) {
                String appName = getApplicationNameByPackageName(context.get(), enablePackagesFile.getName());
                if (null != appName && !appName.isEmpty()) {
                    Package pkg = new Package();
                    pkg.setPackageName(enablePackagesFile.getName());
                    pkg.setName(appName);
                    packages.add(pkg);
                }
            }
            return packages;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            swipeRefreshLayout.get().setRefreshing(true);
        }

        @Override
        protected void onPostExecute(List<Package> packages) {
            super.onPostExecute(packages);
            adapter.setPackages(packages);
            adapter.notifyDataSetChanged();
            swipeRefreshLayout.get().setRefreshing(false);
        }
    }

    class ConfiguredPackagesAdapter extends RecyclerView.Adapter<ConfiguredPackagesAdapter.ViewHolder> {
        private List<Package> packages = new ArrayList<>();

        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            return new ViewHolder(getLayoutInflater().inflate(R.layout.activity_configured_packages_recycler_item, parent, false));
        }

        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            final Package pkg = packages.get(position);
            holder.mTextName.setText(pkg.getName());
            // show configuration brightness dialog
            @SuppressLint("InflateParams") final View contentView = getLayoutInflater().inflate(R.layout.activity_configured_packages_brightness_dialog, null, false);
            final CheckBox checkBox = contentView.findViewById(R.id.activity_configured_packages_brightness_dialog_check_follow_system);
            final SeekBar seekBar = contentView.findViewById(R.id.activity_configured_packages_brightness_dialog_seek_brightness);
            int level = GameModeUtil.getBrightnessLevel(getContext(), pkg.getPackageName());
            seekBar.setProgress(level >= 0 ? level : 0);
            seekBar.setEnabled(-1 != level);
            checkBox.setChecked(-1 == level);
            checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> seekBar.setEnabled(!isChecked));
            holder.itemView.setOnClickListener(v -> new AlertDialog.Builder(getContext())
                    .setTitle(R.string.activity_configured_packages_brightness_dialog_title)
                    .setView(contentView)
                    .setPositiveButton(android.R.string.ok, ((dialog, which) -> {
                        if (checkBox.isChecked()) {
                            // follow system
                            if (!GameModeUtil.setBrightnessLevel(getContext(), pkg.getPackageName(), -1)) {
                                Toast.makeText(getContext(), R.string.activity_configured_packages_brightness_dialog_configure_brightness_failed, Toast.LENGTH_SHORT).show();
                            }
                        } else {
                            // custom
                            if (!GameModeUtil.setBrightnessLevel(getContext(), pkg.getPackageName(), seekBar.getProgress())) {
                                Toast.makeText(getContext(), R.string.activity_configured_packages_brightness_dialog_configure_brightness_failed, Toast.LENGTH_SHORT).show();
                            }
                        }
                        dialog.dismiss();
                    }))
                    .setNegativeButton(android.R.string.cancel, ((dialog, which) -> dialog.dismiss()))
                    .show());
        }

        @Override
        public int getItemCount() {
            return packages.size();
        }

        void setPackages(List<Package> packages) {
            this.packages = packages;
        }

        class ViewHolder extends RecyclerView.ViewHolder {
            @BindView(R.id.activity_configured_packages_recycler_item_txt_name)
            TextView mTextName;

            ViewHolder(@NonNull View itemView) {
                super(itemView);
                ButterKnife.bind(this, itemView);
            }
        }
    }
}
